//============================================================================
// Name        : path.cpp
// Author      : dfoelber
//============================================================================

// INCLUDES //
#include "physics/path.h"
#include <iostream>
//////////////

using namespace std;

/**
* Default constructor.
**/
Path::Path()
{
	x = 0;
	y = 0;
	xVel = yVel = 0;
	xDistance = yDistance = 0;
	rotation = 0;
	keyDir = DIRECTION_NONE;
	rotating = false;
	area = NULL;
}

/**
* Deconstructor
**/
Path::~Path()
{
	if( this->area )
	{
		delete this->area;
	}
}

/**
* Lets the path know that time has passed and to move accordingly.
* 
* @param ms The time passed since last called
**/
void Path::TimePassed( int ms )
{
	// do nothing when time passes
}

/**
* Input that can be used by the path.
* 
* @param event The event
* @return If the event was consumed
**/
bool Path::Input( SDL_Event event )
{
	// ignore input
    return false;
}

/**
* Check if this path collided with another path.
* 
* @param other The other path.
**/
void Path::CheckCollision( Path* other )
{
	bool collided = area->Intersects(other->GetArea(), GetXDistance(), GetYDistance(), other->GetXDistance(), other->GetYDistance() );
	
	/*if( rotating )
	{
		for( int i = 0; i < (int)GetAssociations().size(); i++ )
		{
			GetAssociations()[i]->PuzzleEventOccurred( ROTATION_COLLISION );
		}
	}
	else
	{
		if( (int)(side & SIDE_LEFT) == SIDE_LEFT )
		{
			if( xDistance < 0 )
				xDistance = 0;
			
			for( int i = 0; i < (int)GetAssociations().size(); i++ )
			{
				GetAssociations()[i]->MoveDistance(GetAssociations()[i]->GetXDistance() * -1, 0);
			}
		}
		else if( (int)(side & SIDE_RIGHT) == SIDE_RIGHT )
		{
			if( xDistance > 0 )
				xDistance = 0;
			
			for( int i = 0; i < (int)GetAssociations().size(); i++ )
			{
				GetAssociations()[i]->MoveDistance(GetAssociations()[i]->GetXDistance() * -1, 0);
			}
		}
		else if( (int)(side & SIDE_BOTTOM) == SIDE_BOTTOM )
		{
			if( yDistance > 0 )
				yDistance = other->GetY() - GetHeight() - GetY();
			
			for( int i = 0; i < (int)GetAssociations().size(); i++ )
			{
				GetAssociations()[i]->MoveDistance(0, GetAssociations()[i]->GetYDistance() * -1);
				GetAssociations()[i]->MoveDistance(0, yDistance);
			}
		}
		else if( (int)(side & SIDE_TOP) == SIDE_TOP )
		{
			if( yDistance < 0 )
				yDistance = GetY() - (other->GetY() + other->GetHeight()) + 1;
			
			for( int i = 0; i < (int)GetAssociations().size(); i++ )
			{
				GetAssociations()[i]->MoveDistance(0, GetAssociations()[i]->GetYDistance() * -1);
				GetAssociations()[i]->MoveDistance(0, yDistance);
			}
		}
	}*/
}

/**
* Sets the position of the path.
* 
* @param x The new X coordinate
* @param y The new Y coordinate
**/
void Path::SetPosition( int x, int y )
{
	this->x = x;
	this->y = y;
}

/**
* Sets the size of the path.
* 
* @param width The new width
* @param height The new height
**/
void Path::SetSize( int width, int height )
{
	this->width = width;
	this->height = height;
}

/**
* Gets the width of the path.
* 
* @return The current width
**/
int Path::GetWidth() const
{
	return width;
}

/**
* Gets the height of the path.
* 
* @return The current height
**/
int Path::GetHeight() const
{
	return height;
}

/**
* Gets the X coordinate of the path.
* 
* @return The current X coordinate
**/
int Path::GetX() const
{
	return (int)x;
}

/**
* Gets the Y coordinate of the path.
* 
* @return The current Y coordinate
**/
int Path::GetY() const
{
	return (int)y;
}

/**
* Gets the X velocity of the path.
* 
* @return The current X velocity
**/
double Path::GetXVel() const
{
	return xVel;
}

/**
* Gets the Y velocity of the path.
* 
* @return The current Y velocity
**/
double Path::GetYVel() const
{
	return yVel;
}

/**
* Gets the planned X distance of the path.
* 
* @return The currently planned X distance
**/
double Path::GetXDistance() const 
{ 
	return xDistance; 
}

/**
* Gets the planned Y distance of the path.
* 
* @return The currently planned Y distance
**/
double Path::GetYDistance() const 
{ 
	return yDistance; 
}

/**
* Sets the key direction.
* 
* @param direction The key direction to set
**/
void Path::SetKeyDirection( Direction direction )
{
	keyDir = direction;
}
	
/**
* Gets the key direction.
* 
* @return The current key direction
**/
Path::Direction Path::GetKeyDirection() const
{
	return keyDir;
}

/**
* Adds another path to this path's association list. Transfers ownership to the path.
* 
* @param path the path to add
**/
void Path::AddAssociation( Path* path )
{
	for( int i = 0; i < (int)associations.size(); i++ )
	{
		if( path == associations[i] )
			return;
	}
	
	associations.push_back( path );
	
	path->AddAssociation(this);
}

/**
* Removes a specific path to this path's association list.
* 
* @param path the path to remove
**/
void Path::RemoveAssociation( Path* path )
{
	vector<Path*>::iterator iterator;
	for( iterator = associations.begin(); iterator != associations.end(); iterator++ )
	{
		if( path == *iterator )
		{
			associations.erase( iterator );
			path->RemoveAssociation( this );
		}
	}
}

/**
* Removes all paths from this path's association list.
**/
void Path::RemoveAllAssociations()
{
	associations.clear();
}

/**
* Accessor to the path's association list.
* 
* @return the association list
**/
const vector<Path*>& Path::GetAssociations()
{
	return associations;
}

/**
* Notifies the path that an event has occurred.
* 
* @param event The event that occurred
**/
void Path::PuzzleEventOccurred( PuzzleEvent event )
{
}

/**
* Sets if the path is rotating.
* 
* @param rotate If the path is rotating
**/
void Path::SetRotating( bool rotate )
{
	rotating = rotate;
}

/**
* Advances the path, applying its x and y distances.
**/
void Path::Advance()
{
	x += xDistance; y += yDistance;
	xDistance = yDistance = 0;
	
	SetRotating(false);
}

/**
* Moves the path by the distance supplied.
* 
* @param x The X distance to move the path
* @param x The Y distance to move the path
**/
void Path::MoveDistance(double x, double y)
{
	xDistance += x;
	yDistance += y;
}

/**
* Gets if the path is still moving.
* 
* @return If the path is moving
**/
bool Path::IsMoving()
{
	bool moving = false;
	
	vector<Path*>::iterator iterator;
	for( iterator = associations.begin(); iterator != associations.end(); iterator++ )
	{
		if( (*iterator)->IsMoving() )
			moving = true;
	}
	
	return moving;
}

/**
* Sets the area with a new area.
* 
* @param area The new area.
**/
void Path::SetArea(Area* area)
{
	if( this->area )
	{
		delete this->area;
	}
	
	this->area = area;
}
